"use strict";
/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const LOOP_MAX = 50;
const VARRAY_LENGHT = 9;
const NORMAL_LENGHT = 6;
const HALF_NUMBER = 2;
const ARRAY_MAX_COUNT_FOUR = 4;
const ARRAY_MAX_COUNT_THR = 3;
const ARRAY_INDEX_TWO = 2;
const ARRAY_INDEX_THREE = 3;
const ARRAY_INDEX_FIVE = 5;
const ARRAY_INDEX_SIX = 6;
const ARRAY_INDEX_EIGHT = 8;
const ARRAY_INDEX_SEVEN = 7;
const ARRAY_INDEX_NINE = 9;
const ARRAY_INDEX_TEN = 10;
const ARRAY_INDEX_ELEVEN = 11;
const LINEAR_MEASURE = 180;
const VALIDATION_TWENTY = 20;
const VALIDATION_TWENTY_VALUE = 2889.0000000000045;
const VALIDATION_FORTY = 40;
const VALIDATION_FORTY_VALUE = 2889.0000000000055;
const VALIDATION_EIGHT = 80;
const VALIDATION_EIGHT_VALUE = 2889.000000000005;
const VALIDATION_OHS = 160;
const VALIDATION_OHS_VALUE = 2889.0000000000055;
const QARRAY_ONE_VALUE = 150;
const TIME_UNIT = 1000;
const TIME_COUNT = 9;
const DRAW_QUBE_COUNT = 5;
class Object2 {
    constructor() {
        this.v = new Array();
    }
}
class Object1 {
    constructor() {
        this.loopCount = 0;
        this.loopMax = LOOP_MAX;
        this.timeMax = 0;
        this.timeAvg = 0;
        this.timeMin = 0;
        this.timeTemp = 0;
        this.timeTotal = 0;
        this.init = false;
    }
}
class CreateP {
    constructor(x, y, z) {
        this.v = [x, y, x, 1];
    }
}
class Q {
    constructor() {
        this.vArray = new Array(VARRAY_LENGHT);
        this.edge = new Array();
        this.normal = new Array(NORMAL_LENGHT);
        this.line = new Array();
        this.numPx = 0;
        this.lastPx = 0;
    }
}
class Cube {
    constructor() {
        this.q = new Q();
        // transformation matrix
        this.mTrans = new Array();
        // position information of qube
        this.mQube = new Array();
        // entity matrix
        this.i = new Array();
        this.origin = new Object2();
        this.testing = new Object1();
        this.validation = new Map([
            [VALIDATION_TWENTY, VALIDATION_TWENTY_VALUE],
            [VALIDATION_FORTY, VALIDATION_FORTY_VALUE],
            [VALIDATION_EIGHT, VALIDATION_EIGHT_VALUE],
            [VALIDATION_OHS, VALIDATION_OHS_VALUE]
        ]);
    }
    util(z1, z2) {
        if (z2 >= z1) {
            return 1;
        }
        else {
            return -1;
        }
    }
    drawLine(from, to) {
        let x1 = from.v[0];
        let x2 = to.v[0];
        let y1 = from.v[1];
        let y2 = to.v[1];
        let dx = Math.abs(x2 - x1);
        let dy = Math.abs(y2 - y1);
        let x = x1;
        let y = y1;
        let incX1;
        let incY1;
        let incX2;
        let incY2;
        let den;
        let num;
        let numAdd;
        let numPix;
        incX1 = this.util(x1, x2);
        incX2 = incX1;
        incY1 = this.util(y1, y2);
        incY2 = incY1;
        if (dx >= dy) {
            incX1 = 0;
            incY2 = 0;
            den = dx;
            num = dx / HALF_NUMBER;
            numAdd = dy;
            numPix = dx;
        }
        else {
            incX2 = 0;
            incY1 = 0;
            den = dy;
            num = dy / HALF_NUMBER;
            numAdd = dx;
            numPix = dy;
        }
        numPix = this.q.lastPx + numPix;
        for (let i = this.q.lastPx; i < numPix; i++) {
            num += numAdd;
            if (num >= den) {
                x += incX1;
                y += incY1;
            }
            x += incX2;
            y += incY2;
        }
        this.q.lastPx = numPix;
    }
    calcCross(v0, v1) {
        let cross = [0, 0, 0, 0];
        cross[0] = v0[1] * v1[ARRAY_INDEX_TWO] - v0[ARRAY_INDEX_TWO] * v1[1];
        cross[1] = v0[ARRAY_INDEX_TWO] * v1[0] - v0[0] * v1[ARRAY_INDEX_TWO];
        cross[ARRAY_INDEX_TWO] = v0[0] * v1[1] - v0[1] * v1[0];
        return cross;
    }
    calcNormal(v0, v1, v2) {
        let a = [0, 0, 0, 0];
        let b = [0, 0, 0, 0];
        for (let i = 0; i < ARRAY_MAX_COUNT_THR; i++) {
            a[i] = v0[i] - v1[i];
            b[i] = v2[i] - v1[i];
        }
        a = this.calcCross(a, b);
        let x = a[0] * a[0] + a[1] * a[1] + a[ARRAY_INDEX_TWO] * a[ARRAY_INDEX_TWO];
        let length = Math.sqrt(x);
        for (let i = 0; i < ARRAY_MAX_COUNT_THR; i++) {
            a[i] = a[i] / length;
        }
        a[ARRAY_INDEX_THREE] = 1;
        return a;
    }
    mMulti(m1, m2) {
        let m = [
            [0, 0, 0, 0],
            [0, 0, 0, 0],
            [0, 0, 0, 0],
            [0, 0, 0, 0]
        ];
        for (let i = 0; i < ARRAY_MAX_COUNT_FOUR; i++) {
            for (let j = 0; j < ARRAY_MAX_COUNT_FOUR; j++) {
                m[i][j] =
                    m1[i][0] * m2[0][j] + m1[i][1] * m2[1][j] + m1[i][ARRAY_INDEX_TWO] * m2[ARRAY_INDEX_TWO][j] + m1[i][ARRAY_INDEX_THREE] * m2[ARRAY_INDEX_THREE][j];
            }
        }
        return m;
    }
    vMulti(m, v) {
        let vect = [0, 0, 0, 0];
        for (let i = 0; i < ARRAY_MAX_COUNT_FOUR; i++) {
            vect[i] = m[i][0] * v[0] + m[i][1] * v[1] + m[i][ARRAY_INDEX_TWO] * v[ARRAY_INDEX_TWO] + m[i][ARRAY_INDEX_THREE] * v[ARRAY_INDEX_THREE];
        }
        return vect;
    }
    vMulti2(m, v) {
        let vect = [0, 0, 0, 0];
        for (let i = 0; i < ARRAY_MAX_COUNT_FOUR; i++) {
            vect[i] = m[i][0] * v[0] + m[i][1] * v[1] + m[i][ARRAY_INDEX_TWO] * v[ARRAY_INDEX_TWO];
        }
        return vect;
    }
    translate(m, dx, dy, dz) {
        let t = [
            [1, 0, 0, dx],
            [0, 1, 0, dy],
            [0, 0, 1, dz],
            [0, 0, 0, 1]
        ];
        return this.mMulti(t, m);
    }
    rotateX(m, phi) {
        let a = phi;
        a *= Math.PI / LINEAR_MEASURE;
        let cos = Math.cos(a);
        let sin = Math.sin(a);
        let r = [
            [1, 0, 0, 0],
            [0, cos, -sin, 0],
            [0, sin, cos, 0],
            [0, 0, 0, 1]
        ];
        return this.mMulti(r, m);
    }
    rotateY(m, phi) {
        let a = phi;
        a *= Math.PI / LINEAR_MEASURE;
        let cos = Math.cos(a);
        let sin = Math.sin(a);
        let r = [
            [cos, 0, sin, 0],
            [0, 1, 0, 0],
            [-sin, 0, cos, 0],
            [0, 0, 0, 1]
        ];
        return this.mMulti(r, m);
    }
    rotateZ(m, phi) {
        let a = phi;
        a *= Math.PI / LINEAR_MEASURE;
        let cos = Math.cos(a);
        let sin = Math.sin(a);
        let r = [
            [cos, -sin, 0, 0],
            [sin, cos, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ];
        return this.mMulti(r, m);
    }
    drawLine1(curN) {
        if (curN[0][ARRAY_INDEX_TWO] < 0) {
            if (!this.q.line[0]) {
                this.drawLine(this.q.vArray[0], this.q.vArray[1]);
                this.q.line[0] = true;
            }
            if (!this.q.line[1]) {
                this.drawLine(this.q.vArray[1], this.q.vArray[ARRAY_INDEX_TWO]);
                this.q.line[1] = true;
            }
            if (!this.q.line[ARRAY_INDEX_TWO]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_TWO], this.q.vArray[ARRAY_INDEX_TWO]);
                this.q.line[ARRAY_INDEX_TWO] = true;
            }
            if (!this.q.line[ARRAY_INDEX_TWO]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_THREE], this.q.vArray[0]);
                this.q.line[ARRAY_INDEX_TWO] = true;
            }
        }
        if (curN[1][ARRAY_INDEX_TWO] < 0) {
            if (!this.q.line[ARRAY_INDEX_TWO]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_THREE], this.q.vArray[ARRAY_INDEX_TWO]);
                this.q.line[ARRAY_INDEX_TWO] = true;
            }
            if (!this.q.line[ARRAY_INDEX_NINE]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_THREE], this.q.vArray[ARRAY_INDEX_SIX]);
                this.q.line[ARRAY_INDEX_NINE] = true;
            }
            if (!this.q.line[ARRAY_INDEX_SIX]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_SIX], this.q.vArray[ARRAY_INDEX_SEVEN]);
                this.q.line[ARRAY_INDEX_SIX] = true;
            }
            if (!this.q.line[ARRAY_INDEX_TEN]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_SEVEN], this.q.vArray[ARRAY_INDEX_THREE]);
                this.q.line[ARRAY_INDEX_TEN] = true;
            }
        }
    }
    drawLine2(curN) {
        if (curN[ARRAY_INDEX_THREE][ARRAY_INDEX_THREE] < 0) {
            if (!this.q.line[ARRAY_MAX_COUNT_FOUR]) {
                this.drawLine(this.q.vArray[ARRAY_MAX_COUNT_FOUR], this.q.vArray[ARRAY_INDEX_FIVE]);
                this.q.line[ARRAY_MAX_COUNT_FOUR] = true;
            }
            if (!this.q.line[ARRAY_INDEX_FIVE]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_FIVE], this.q.vArray[ARRAY_INDEX_SIX]);
                this.q.line[ARRAY_INDEX_FIVE] = true;
            }
            if (!this.q.line[ARRAY_INDEX_SIX]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_SIX], this.q.vArray[ARRAY_INDEX_SEVEN]);
                this.q.line[ARRAY_INDEX_SIX] = true;
            }
            if (!this.q.line[ARRAY_INDEX_SEVEN]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_SEVEN], this.q.vArray[ARRAY_MAX_COUNT_FOUR]);
                this.q.line[ARRAY_INDEX_SEVEN] = true;
            }
        }
        if (curN[ARRAY_INDEX_THREE][ARRAY_INDEX_THREE] < 0) {
            if (!this.q.line[ARRAY_MAX_COUNT_FOUR]) {
                this.drawLine(this.q.vArray[ARRAY_MAX_COUNT_FOUR], this.q.vArray[ARRAY_INDEX_FIVE]);
                this.q.line[ARRAY_MAX_COUNT_FOUR] = true;
            }
            if (!this.q.line[ARRAY_INDEX_EIGHT]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_FIVE], this.q.vArray[1]);
                this.q.line[ARRAY_INDEX_EIGHT] = true;
            }
            if (!this.q.line[0]) {
                this.drawLine(this.q.vArray[1], this.q.vArray[0]);
                this.q.line[0] = true;
            }
            if (!this.q.line[ARRAY_INDEX_ELEVEN]) {
                this.drawLine(this.q.vArray[0], this.q.vArray[ARRAY_MAX_COUNT_FOUR]);
                this.q.line[ARRAY_INDEX_ELEVEN] = true;
            }
        }
    }
    drawQube() {
        let curN = new Array();
        this.q.lastPx = 0;
        for (let i = DRAW_QUBE_COUNT; i >= 0; i--) {
            curN.push(this.vMulti2(this.mQube, this.q.normal[i]));
        }
        this.drawLine1(curN);
        this.drawLine2(curN);
        if (curN[ARRAY_MAX_COUNT_FOUR][ARRAY_INDEX_TWO] < 0) {
            if (!this.q.line[ARRAY_INDEX_ELEVEN]) {
                this.drawLine(this.q.vArray[ARRAY_MAX_COUNT_FOUR], this.q.vArray[0]);
                this.q.line[ARRAY_INDEX_ELEVEN] = true;
            }
            if (!this.q.line[ARRAY_INDEX_THREE]) {
                this.drawLine(this.q.vArray[0], this.q.vArray[ARRAY_INDEX_THREE]);
                this.q.line[ARRAY_INDEX_THREE] = true;
            }
            if (!this.q.line[ARRAY_INDEX_TEN]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_THREE], this.q.vArray[ARRAY_INDEX_SEVEN]);
                this.q.line[ARRAY_INDEX_TEN] = true;
            }
            if (!this.q.line[ARRAY_INDEX_SEVEN]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_SEVEN], this.q.vArray[ARRAY_MAX_COUNT_FOUR]);
                this.q.line[ARRAY_INDEX_SEVEN] = true;
            }
        }
        if (curN[ARRAY_INDEX_FIVE][ARRAY_INDEX_TWO] < 0) {
            if (!this.q.line[ARRAY_INDEX_EIGHT]) {
                this.drawLine(this.q.vArray[1], this.q.vArray[ARRAY_INDEX_FIVE]);
                this.q.line[ARRAY_INDEX_EIGHT] = true;
            }
            if (!this.q.line[ARRAY_INDEX_FIVE]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_FIVE], this.q.vArray[ARRAY_INDEX_SIX]);
                this.q.line[ARRAY_INDEX_FIVE] = true;
            }
            if (!this.q.line[ARRAY_INDEX_NINE]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_SIX], this.q.vArray[ARRAY_INDEX_TWO]);
                this.q.line[ARRAY_INDEX_NINE] = true;
            }
            if (!this.q.line[1]) {
                this.drawLine(this.q.vArray[ARRAY_INDEX_TWO], this.q.vArray[1]);
                this.q.line[1] = true;
            }
        }
        this.q.line = [false, false, false, false, false, false, false, false, false, false, false, false];
        this.q.lastPx = 0;
    }
    loop() {
        if (this.testing.loopCount > this.testing.loopMax) {
            return;
        }
        let testingStr = String(this.testing.loopCount);
        while (testingStr.length < ARRAY_MAX_COUNT_THR) {
            testingStr = '0' + testingStr;
        }
        this.mTrans = this.translate(this.i, -this.q.vArray[ARRAY_INDEX_EIGHT].v[0], -this.q.vArray[ARRAY_INDEX_EIGHT].v[1], -this.q.vArray[ARRAY_INDEX_EIGHT].v[ARRAY_INDEX_TWO]);
        this.mTrans = this.rotateX(this.mTrans, 1);
        this.mTrans = this.rotateY(this.mTrans, ARRAY_MAX_COUNT_THR);
        this.mTrans = this.rotateZ(this.mTrans, ARRAY_INDEX_FIVE);
        this.mTrans = this.translate(this.mTrans, this.q.vArray[ARRAY_INDEX_EIGHT].v[0], this.q.vArray[ARRAY_INDEX_EIGHT].v[1], this.q.vArray[ARRAY_INDEX_EIGHT].v[ARRAY_INDEX_TWO]);
        this.mQube = this.mMulti(this.mTrans, this.mQube);
        for (let i = 8; i >= 0; i--) {
            this.q.vArray[i].v = this.vMulti(this.mTrans, this.q.vArray[i].v);
        }
        this.drawQube();
        this.testing.loopCount += 1;
        this.loop();
    }
    create1(cubeSize) {
        // init/reset vars
        this.origin.v = [QARRAY_ONE_VALUE, QARRAY_ONE_VALUE, VALIDATION_TWENTY, 1];
        this.testing.loopCount = 0;
        this.testing.loopMax = 50;
        this.testing.timeMax = 0;
        this.testing.timeAvg = 0;
        this.testing.timeMin = 0;
        this.testing.timeTemp = 0;
        this.testing.timeTotal = 0;
        this.testing.init = false;
        // transformation matrix
        this.mTrans = [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ];
        // position information of qube
        this.mQube = [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ];
        // entity matrix
        this.i = [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ];
        // create qube
        this.q.vArray[0] = new CreateP(-cubeSize, -cubeSize, cubeSize);
        this.q.vArray[1] = new CreateP(-cubeSize, cubeSize, cubeSize);
        this.q.vArray[ARRAY_INDEX_TWO] = new CreateP(cubeSize, cubeSize, cubeSize);
        this.q.vArray[ARRAY_INDEX_THREE] = new CreateP(cubeSize, -cubeSize, cubeSize);
        this.q.vArray[ARRAY_MAX_COUNT_FOUR] = new CreateP(-cubeSize, -cubeSize, -cubeSize);
        this.q.vArray[ARRAY_INDEX_FIVE] = new CreateP(-cubeSize, cubeSize, -cubeSize);
        this.q.vArray[ARRAY_INDEX_SIX] = new CreateP(cubeSize, cubeSize, -cubeSize);
        this.q.vArray[ARRAY_INDEX_SEVEN] = new CreateP(cubeSize, -cubeSize, -cubeSize);
        this.q.vArray[ARRAY_INDEX_EIGHT] = new CreateP(0, 0, 0);
    }
    create2(cubeSize) {
        // anti-clockwise edge check
        this.q.edge = [
            [0, 1, ARRAY_INDEX_TWO],
            [ARRAY_INDEX_THREE, ARRAY_INDEX_TWO, ARRAY_INDEX_SIX],
            [ARRAY_INDEX_SEVEN, ARRAY_INDEX_SIX, ARRAY_INDEX_FIVE],
            [ARRAY_MAX_COUNT_FOUR, ARRAY_INDEX_FIVE, 1],
            [ARRAY_MAX_COUNT_FOUR, 0, ARRAY_INDEX_THREE],
            [1, ARRAY_INDEX_FIVE, ARRAY_INDEX_SIX]
        ];
        for (let i = 0; i < this.q.edge.length; i++) {
            this.q.normal[i] = this.calcNormal(this.q.vArray[this.q.edge[i][0]].v, this.q.vArray[this.q.edge[i][1]].v, this.q.vArray[this.q.edge[i][ARRAY_INDEX_TWO]].v);
        }
        this.q.line = [false, false, false, false, false, false, false, false, false, false, false, false];
        this.q.numPx = ARRAY_INDEX_NINE * ARRAY_INDEX_TWO * cubeSize;
        for (let i = 0; i < this.q.numPx; i++) {
            new CreateP(0, 0, 0);
        }
        this.mTrans = this.translate(this.mTrans, this.origin.v[0], this.origin.v[1], this.origin.v[ARRAY_INDEX_TWO]);
        this.mQube = this.mMulti(this.mTrans, this.mQube);
        for (let i = 0; i < TIME_COUNT; i++) {
            this.q.vArray[i].v = this.vMulti(this.mTrans, this.q.vArray[i].v);
        }
        this.drawQube();
        this.testing.init = true;
        this.loop();
    }
    creat(cubeSize) {
        this.create1(cubeSize);
        this.create2(cubeSize);
        // debugLog(
        //   'cubeSize is' +
        //     cubeSize +
        //     'this.MTrans value is' +
        //     this.mTrans[0][0] +
        //     this.mTrans[0][1] +
        //     this.mTrans[0][ARRAY_INDEX_TWO] +
        //     this.mTrans[0][ARRAY_INDEX_THREE]
        // );
        // debugLog(
        //   'cubeSize is' +
        //     cubeSize +
        //     'this.MQube value is' +r
        //     this.mQube[0][0] +
        //     this.mQube[0][1] +
        //     this.mQube[0][ARRAY_INDEX_TWO] +
        //     this.mQube[0][ARRAY_INDEX_THREE]
        // );
        // Perform a simple sum-based verification.
        let sum = 0;
        for (let i = 0; i < this.q.vArray.length; i++) {
            let vector = this.q.vArray[i].v;
            for (let j = 0; j < vector.length; j++) {
                sum += vector[j];
            }
        }
        if (sum !== this.validation.get(cubeSize)) {
            //debugLog("Error: bad vector sum for cubeSize = " + cubeSize + "; expected " + this.validation.get(cubeSize) + " but got " + sum)
        }
    }
    runTest() {
        let i = VALIDATION_TWENTY;
        while (i <= VALIDATION_OHS) {
            this.creat(i);
            i *= ARRAY_INDEX_TWO;
        }
    }
}
let isDebug = false;
function debugLog(msg) {
    if (isDebug) {
        console.log(msg);
    }
}
/*
 * @State
 * @Tags Jetstream2
 */
class Benchmark {
    /*
     * @Benchmark
     */
    runIterationTime() {
        let start = Date.now();
        let cube = new Cube();
        for (let i = 0; i < ARRAY_INDEX_EIGHT; i++) {
            cube.runTest();
        }
        let end = Date.now();
        console.log('3d-cube: ms = ' + (end - start));
    }
}
new Benchmark().runIterationTime();
